package de.heimlich.gut;

/**
 * Copyright (C) 2009 Till Essers
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the 
 * GNU General Public License as published by the Free Software Foundation; 
 * either version 3 of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, see <http://www.gnu.org/licenses/>.
 */

import java.util.Date;
import java.util.HashMap;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Contacts;
import android.provider.Contacts.People;
import android.sax.StartElementListener;
import android.telephony.gsm.SmsMessage;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;

public class MessagesProvider extends AppWidgetProvider {



	/** TAG used for Debug-Logging */
	private static final String LOG_TAG = "MessagesWidget";
	
	/** 
	 * The Action fired by the Android-System when a SMS was received.
	 */
	private static final String SMS_RECVEICED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
	
	/**
	 * Actions fired by the widget to react to the buttons
	 */
	public static final String SHOW_NEXT_SMS_ACTION = "de.heimlich.gut.MessagesWidget.SHOW_NEXT_SMS";
	public static final String SHOW_PREVIOUS_SMS_ACTION = "de.heimlich.gut.MessagesWidget.SHOW_PREVIOUS_SMS";
	
	/**
	 * Projection array used to query the contacts.
	 */
	private static final String[] contact_projection = new String[] {
            Contacts.Phones.PERSON_ID,
            People.DISPLAY_NAME
         };
	
	/**
	 * Cursor containing all sms stored in the sms/inbox
	 */
//	private static Cursor sms_cursor;
	
	/**
	 * Current position inside the cursor of the shown sms
	 */
//	private static int position = -1;
	
	private static final String PREFS_NAME = "MessagesWidgetPreferences";
	
	private static final String PREFS_POS = "SmsPosition";
	
	private static HashMap<Integer, int[]> SmsIdMap = new HashMap<Integer, int[]>(); 
	
	private static WidgetPreferences preferences = null;

	public MessagesProvider() {
		// TODO Auto-generated constructor stub
	}
	@Override
	public void onDisabled(Context context) {

		super.onDisabled(context);
	}
	
	@Override
	public void onEnabled(Context context) {
		super.onEnabled(context);
	}
	
	public static WidgetPreferences getPreferences(Context context) {
		if(preferences == null) preferences = new WidgetPreferences(context);
		return preferences;
	}
	
	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
//		if(sms_cursor != null) sms_cursor.close();
		
		//removing the position from the preferences so that a new widget would start from 0
		SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
		SharedPreferences.Editor editor = prefs.edit();
		editor.putInt(PREFS_POS, 0);
		editor.commit();
		super.onDeleted(context, appWidgetIds);
	}

	@Override
	 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
		// To prevent any ANR timeouts, we perform the update in a service
//	    context.startService(new Intent(context, UpdateService.class));
//		 sms_cursor = getSmsCursor(context, true);
//		 
//		 doBuildUpdate(context, sms_cursor);
	 }
	
//	private static Cursor getSmsCursor(Context context, boolean createNew) {
//		Cursor sms_cursor = null;
//		if(MessagesProvider.sms_cursor != null && createNew ||
//				MessagesProvider.sms_cursor == null || createNew) {
//			Log.v(LOG_TAG, "no sms_cursor present or should create a new one.");
//			ContentResolver cr = context.getContentResolver();
//			sms_cursor = cr.query(SMSConstants.CONTENT_URI,SMSConstants.projection,null,null,null);
//			sms_cursor.moveToFirst();
//			Log.v(LOG_TAG, "finished query. found "+sms_cursor.getCount()+" sms in the inbox");
//			if(position == -1 || createNew)
//				MessagesProvider.position = sms_cursor.getPosition();
//		} else {
//			sms_cursor = MessagesProvider.sms_cursor;
//		}
//		return sms_cursor;
//	}
	
//	private static void doBuildUpdate(Context context, Cursor sms_cursor) {
//		doBuildUpdate(context, sms_cursor, R.layout.main);
//	}
//	
//
//	private static void doBuildUpdate(Context context, Cursor sms_cursor, int layout) {
//		Log.v(LOG_TAG, "start building GUI Update");
//		RemoteViews view = new RemoteViews(context.getPackageName(),  layout);
//		
//		Cursor contact_cursor = doContactLookupByID(context, sms_cursor.getString(SMSConstants.PERSON_INT));
//		java.text.DateFormat df = DateFormat.getDateFormat(context);
//		java.text.DateFormat tf = DateFormat.getTimeFormat(context);
//		Date date = new Date(sms_cursor.getLong(SMSConstants.DATE_INT));
//		view.setTextViewText(R.id.DateView, df.format(date) + " " + tf.format(date));
//		view.setTextViewText(R.id.MessageView, sms_cursor.getString(SMSConstants.BODY_INT));
////		msg = sms_cursor.getString(SMSConstants.BODY_INT);
//		if(contact_cursor != null) {
//			view.setTextViewText(R.id.ContactView, contact_cursor.getString(1));
//			Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, contact_cursor.getLong(0));
//			Bitmap bitmap = People.loadContactPhoto(context, uri, R.drawable.android_icon_48, null);
//			bitmap = Bitmap.createScaledBitmap(bitmap, 48, 48, false);
//			view.setBitmap(R.id.ContactPic, "setImageBitmap", bitmap);
//		} else {
//			view.setTextViewText(R.id.ContactView, sms_cursor.getString(SMSConstants.ADDRESS_INT));
//			view.setBitmap(R.id.ContactPic, "setImageBitmap", 
//					BitmapFactory.decodeResource(context.getResources(),R.drawable.android_icon_48));
//		}
//		if(sms_cursor.getCount() > position) {
//			Intent intent = new Intent(context, MessagesProvider.class);
//			intent.setAction(SHOW_NEXT_SMS_ACTION);
//			PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
//			view.setOnClickPendingIntent(R.id.NextButton, pi);
//			view.setViewVisibility(R.id.NextButton, View.VISIBLE);
//		}else{
//			view.setViewVisibility(R.id.NextButton, View.INVISIBLE);
//		}
//		if(0 < position){
//			Intent intent = new Intent(context, MessagesProvider.class);
//			intent.setAction(SHOW_PREVIOUS_SMS_ACTION);
//			PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
//			view.setOnClickPendingIntent(R.id.PrevButton, pi);
//			view.setViewVisibility(R.id.PrevButton, View.VISIBLE);
//		}else{
//			view.setViewVisibility(R.id.PrevButton, View.INVISIBLE);
//		}
////		
////		Intent intent = new Intent(Intent.ACTION_VIEW);
////		intent.addCategory(Intent.CATEGORY_DEFAULT);
////		intent.setData(Uri.parse("content://mms-sms/threadID/"+sms_cursor.getString(SMSConstants.THREAD_ID_INT)));
////		view.setOnClickPendingIntent(R.id.MessageView, PendingIntent.getActivity(context, 0, intent, 0));
//		Intent intent = new Intent(context, MessagesProvider.class);
//		intent.setAction("Scroll_Text");
//		PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
//		view.setOnClickPendingIntent(R.id.MessageView, pi);
//		view.setTextViewText(R.id.PositionView, (position +1)+ "/" + (sms_cursor.getCount() +1));
//		ComponentName thisWidget = new ComponentName(context, MessagesProvider.class);
//        AppWidgetManager manager = AppWidgetManager.getInstance(context);
//        if(contact_cursor != null) contact_cursor.close();
//        manager.updateAppWidget(thisWidget, view);
//        Log.v(LOG_TAG,	"finished building GUI update");
//	}
	
	public static void addNewWidget(Context context, int widgetId) {
		if(!SmsIdMap.containsKey(widgetId))
			SmsIdMap.put(widgetId, null);
	}

	public static void doBuildUpdate(Context context, SmsMmsMessage message, int layout, int widgetId) {
		Log.v(LOG_TAG, "start building GUI Update");
		RemoteViews view = new RemoteViews(context.getPackageName(),  layout);
		int position = getPreferences(context).getPosition(widgetId);
		view.setTextViewText(R.id.DateView, message.getFormattedTimestamp());
		view.setTextViewText(R.id.MessageView, message.getMessageBody());
		view.setTextViewText(R.id.ContactView, message.getContactName());
		
		if(message.getContactId() != null) {
			Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, Integer.parseInt(message.getContactId()));
			Bitmap bitmap = People.loadContactPhoto(context, uri, R.drawable.android_icon_48, null);
			bitmap = Bitmap.createScaledBitmap(bitmap, 54, 54, true);
			view.setBitmap(R.id.ContactPic, "setImageBitmap", bitmap);
		} else {
			view.setBitmap(R.id.ContactPic, "setImageBitmap", 
					BitmapFactory.decodeResource(context.getResources(),R.drawable.android_icon_48));
		}
		int sms_count = SmsPopupUtils.getSmsInboxCount(context) ;
		if(sms_count > position) {
			Intent intent = new Intent(context, MessagesProvider.class);
			intent.setAction(SHOW_NEXT_SMS_ACTION);
			intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
			PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
			view.setOnClickPendingIntent(R.id.NextButton, pi);
			view.setViewVisibility(R.id.NextButton, View.VISIBLE);
		}else{
			view.setViewVisibility(R.id.NextButton, View.INVISIBLE);
		}
		if(0 < position){
			Intent intent = new Intent(context, MessagesProvider.class);
			intent.setAction(SHOW_PREVIOUS_SMS_ACTION);
			intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
			
			PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
			view.setOnClickPendingIntent(R.id.PrevButton, pi);
			view.setViewVisibility(R.id.PrevButton, View.VISIBLE);
		}else{
			view.setViewVisibility(R.id.PrevButton, View.INVISIBLE);
		}
//		
//		Intent intent = new Intent(Intent.ACTION_VIEW);
//		intent.addCategory(Intent.CATEGORY_DEFAULT);
//		intent.setData(Uri.parse("content://mms-sms/threadID/"+sms_cursor.getString(SMSConstants.THREAD_ID_INT)));
//		view.setOnClickPendingIntent(R.id.MessageView, PendingIntent.getActivity(context, 0, intent, 0));
		Intent intent = new Intent(context, MessagesProvider.class);
		intent.setAction("Scroll_Text");
		PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
		view.setOnClickPendingIntent(R.id.MessageView, pi);
		view.setTextViewText(R.id.PositionView, (position +1)+ "/" + (sms_count +1));
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(widgetId, view);
        Log.v(LOG_TAG,	"finished building GUI update");
	}
	
	
	
	@Override
	public void onReceive(Context context, Intent intent) {
		try {
		String action = intent.getAction();
		int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
		WidgetPreferences preferences = getPreferences(context);
		int position = preferences.getPosition(widgetId);
		int[] ids = SmsIdMap.get(widgetId);
		if(ids == null) {
			ids = SmsPopupUtils.getSmsIdsFromInbox(context);
			SmsIdMap.put(widgetId, ids);
		}
		if (action.equals(SHOW_NEXT_SMS_ACTION)) {
			++position;
			preferences.setPosition(position, widgetId);

			doBuildUpdate(context, SmsPopupUtils.getSmsDetailsById(context, 
					ids[position]), preferences.getLayout(widgetId),widgetId);
			
		}else if (action.equals(SHOW_PREVIOUS_SMS_ACTION)) {
			--position;
			preferences.setPosition(position, widgetId);

			doBuildUpdate(context, SmsPopupUtils.getSmsDetailsById(context, 
					ids[position]), preferences.getLayout(widgetId), widgetId);
		}else if(intent.getAction().equals("Scroll_Text")){
			SmsMmsMessage msg = SmsPopupUtils.getSmsDetailsById(context, ids[position]);
			Intent popup = msg.getPopupIntent();
			context.startActivity(popup);
		}else if (intent.getAction().equals(SMS_RECVEICED_ACTION)) {
			int[] widgetIds = AppWidgetManager.getInstance(context)
					.getAppWidgetIds(new ComponentName(context, MessagesProvider.class));
			position = 0;
            /* The SMS-Messages are 'hiding' within the extras of the Intent. */
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
            	 SmsMmsMessage msg = new SmsMmsMessage(context, bundle);
            	 //after receiving a new sms we want ALL widgets to show it.
            	 for(int wId : widgetIds)
            		 doBuildUpdate(context, msg, preferences.getLayout(wId), wId);
            }
       } else {
    	   super.onReceive(context, intent);
       }
		}catch (Throwable t) {
			//trying to catch everything that would cause the widget to crash
			Log.e(LOG_TAG, "reached catchall clause, something bad happened in MessagesWidget#onReceive()");
			t.printStackTrace();
		}
	}

	/**
	 * Looks up the contact for the given number and returns the cursor moved 
	 * to the correct object, or <code>null</code> if none is found.
	 * @param context
	 * @param number
	 * @return
	 */
	public static Cursor doContactLookup(Context context, String number) {
		Log.v(LOG_TAG, "starting contact lookup through Contacts.Phones.CONTENT_FILTER_URL");
        Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL,
                Uri.encode(number));
        Cursor cur = context.getContentResolver().query(contactUri, contact_projection, null, null, null);
        if(cur.moveToFirst()) {
        	Log.v(LOG_TAG, "finished contact lookup. found a contact, cursor moving to first element");
        	return cur;
        }
        Log.v(LOG_TAG, "finished contact lookup. found nothing, returning null");
        return null;
	}
	
	public static Cursor doContactLookupByID(Context context, String id) {
		Log.v(LOG_TAG, "starting contact lookup with ID{"+id+"}");
        Cursor cur = context.getContentResolver().query(Contacts.Phones.CONTENT_URI
        		, contact_projection, Contacts.Phones.PERSON_ID +"='"+id+"'"
        		, null, null);
        if(cur.moveToFirst()){
        	Log.v(LOG_TAG, "finished contact lookup, found contact.");
        	return cur;
        }
        Log.v(LOG_TAG, "finished contact lookup, found nothing.");
		return null;
	}
	
}
